package com.huahai.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.huahai.common.ErrorCode;
import com.huahai.constant.RedisConstant;
import com.huahai.exception.BusinessException;
import com.huahai.mapper.UserFollowMapper;
import com.huahai.pojo.entity.User;
import com.huahai.pojo.entity.UserFollow;
import com.huahai.pojo.vo.FollowRelationVO;
import com.huahai.pojo.vo.UserFollowVO;
import com.huahai.pojo.vo.UserVO;
import com.huahai.service.UserFollowService;
import com.huahai.service.UserService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 用户好友关系表接口实现类
 *
 * @author 29095
 */
@Service
public class UserFollowServiceImpl extends ServiceImpl<UserFollowMapper, UserFollow> implements UserFollowService {

    @Resource
    private UserFollowMapper userFollowMapper;

    @Resource
    private UserService userService;

    @Resource
    private RedissonClient redissonClient;

    // 定义关注好友的key
    private static final String ADD_FOLLOW_KEY = "add_follow:";

    /**
     * 关注用户
     *
     * @param userId
     * @param followId
     * @return
     */
    @Override
    public Boolean addFollow(Long userId, Long followId) {
        // 1. 判断请求参数
        if (userId == null || userId < 0) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        if (followId == null || followId < 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在");
        }
        if(userId.equals(followId)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "不能关注自己");
        }
        // 2. 查询关注状态（已关注， 未关注）
        QueryWrapper<UserFollow> userFollowQueryWrapper = new QueryWrapper<>();
        userFollowQueryWrapper.eq("userId", userId);
        userFollowQueryWrapper.eq("followedId", followId);
        long count = this.count(userFollowQueryWrapper);
        if (count > 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "不能重复关注");
        }
        // 3. 若未关注则可以关注
        // 添加分布式锁，防止短时间内单个用户添加多条用户关注数据
        String lockKey = RedisConstant.PROJECT_KEY + RedisConstant.FOllOW_KEY + ADD_FOLLOW_KEY + userId;
        RLock addLock = redissonClient.getLock(lockKey);
        long waitTime = 1000L;
        long leaseTime = 30L;
        try {
            boolean lockResult = addLock.tryLock(waitTime, leaseTime, TimeUnit.SECONDS);
            if (!lockResult) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "关注过于频繁，请稍后重试");
            }
            UserFollow userFollow = new UserFollow();
            userFollow.setUserId(userId);
            userFollow.setFollowedId(followId);
            userFollow.setFollowTime(LocalDateTime.now());
            // 5. 返回结果
            boolean saveResult = this.save(userFollow);
            if (!saveResult) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "关注失败");
            }
            return true;
        } catch (InterruptedException e) {
            log.error("add_follow error", e);
            throw new RuntimeException(e);
        } finally {
            // 判断当前锁是否是该线程的锁
            if (addLock.isHeldByCurrentThread()) {
                addLock.unlock();
            }
        }
    }

    /**
     * 取消关注
     *
     * @param userId
     * @param followId
     * @return
     */
    @Override
    public boolean removeFollow(Long userId, Long followId) {
        // 1. 判断请求参数
        if (userId == null || userId < 0) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        if (followId == null || followId < 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在");
        }
        if(userId.equals(followId)){
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "不能取关自己");
        }
        // 2. 查询当前关注状态是否存在
        QueryWrapper<UserFollow> userFollowQueryWrapper = new QueryWrapper<>();
        userFollowQueryWrapper.eq("userId", userId);
        userFollowQueryWrapper.eq("followedId", followId);
        long count = this.count(userFollowQueryWrapper);
        if (count == 0 || count < 0){
            // 3. 不存在则不允许删除，并抛异常
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户未关注");
        }
        // 4. 存在则执行删除操作
        boolean removeResult = this.remove(userFollowQueryWrapper);
        if(!removeResult){
            throw new BusinessException(ErrorCode.SYSTEM_ERROR, "取消关注失败");
        }
        // 5. 返回结果
        return true;
    }

    /**
     * 获取用户好友列表信息
     *
     * @param loginUser
     * @return
     */
    @Override
    public UserFollowVO listUserFollows(User loginUser) {
        // 1. 请求参数判空
        if (loginUser == null) {
            throw new BusinessException(ErrorCode.NOT_LOGIN);
        }
        // 2. 定义返回的UserFollowVO
        UserFollowVO userFollowVO = new UserFollowVO();
        // 3. 查询当前登录用户的关注列表
        Long userId = loginUser.getId();

        // 3.1 查询并封装关注列表和粉丝列表
        List<FollowRelationVO> followList = queryFollowRelations(userId, "userId");
        List<FollowRelationVO> followerList = queryFollowRelations(userId, "followedId");

        // 4. 计算互相关注列表
        List<FollowRelationVO> mutualList = calculateMutualFollows(followList, followerList);

        // 5. 封装userFollowedVO并返回
        userFollowVO.setUserList(followList);
        userFollowVO.setFollowedUserList(followerList);
        userFollowVO.setUserId(userId);
        userFollowVO.setMutualUserList(mutualList);
        userFollowVO.setUserCount((long) followList.size());
        userFollowVO.setFollowedUserCount((long) followerList.size());
        userFollowVO.setMutualUserCount((long) mutualList.size());
        return userFollowVO;
    }

    /**
     * 通用方法：查询关注关系并封装为视图对象列表
     *
     * @param userId     用户ID
     * @param matchField 匹配字段："userId"表示查询该用户关注的人，"followedId"表示查询关注该用户的人
     * @return 关注关系视图对象列表
     */
    private List<FollowRelationVO> queryFollowRelations(Long userId, String matchField) {
        // 1. 创建查询条件
        QueryWrapper<UserFollow> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(matchField, userId);
        queryWrapper.orderByDesc("followTime");
        List<UserFollow> queryList = this.list(queryWrapper);
        // 2. 判空处理
        if (CollectionUtils.isEmpty(queryList)) {
            return Collections.emptyList();
        }
        // 3. 封装关系视图对象
        return queryList.stream().map(userFollow -> {
            FollowRelationVO relationVO = new FollowRelationVO();
            relationVO.setFollowTime(userFollow.getFollowTime());
            // 获取用户ID（根据查询条件不同，用户ID来源不同）
            Long targetUserId = "userId".equals(matchField) ? userFollow.getFollowedId() : userFollow.getUserId();
            // 封装用户信息
            User followUser = userService.getById(targetUserId);
            UserVO userVO = new UserVO();
            BeanUtils.copyProperties(followUser, userVO);
            relationVO.setUser(userVO);

            return relationVO;
        }).collect(Collectors.toList());
    }

    /**
     * 计算互相关注列表
     *
     * @param followList   关注列表
     * @param followerList 粉丝列表
     * @return 互相关注列表
     */
    private List<FollowRelationVO> calculateMutualFollows(
            List<FollowRelationVO> followList,
            List<FollowRelationVO> followerList) {

        // 快速查找：将粉丝列表中的用户ID存入Set
        Set<Long> followerUserIdSet = followerList.stream()
                .map(relation -> relation.getUser().getId())
                .collect(Collectors.toSet());

        // 遍历关注列表，找出同时存在于粉丝列表中的用户
        return followList.stream()
                .filter(relation -> followerUserIdSet.contains(relation.getUser().getId()))
                .collect(Collectors.toList());
    }

    /**
     * 判断用户是否关注了目标用户
     * @param userId 用户ID
     * @param followId 目标用户ID
     * @return true-已关注，false-未关注
     */
    @Override
    public boolean isUserFollowed(Long userId, Long followId) {
        // 查询用户是否已关注目标用户
        QueryWrapper<UserFollow> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userId", userId)
                .eq("followedId", followId);

        return userFollowMapper.exists(queryWrapper);
    }

}




